package controllers.baseAPI;

import admin.AdminUser;
import admin.AdminUserRole;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import com.google.gson.Gson;
import helper.BeanHelper;
import models.base.*;
import org.apache.commons.lang.StringEscapeUtils;
import play.Logger;
import play.data.validation.Error;
import play.data.validation.Validation;
import play.i18n.Messages;
import play.libs.IO;
import play.modules.paginate.Paginator;
import play.mvc.Before;
import play.mvc.Controller;
import play.mvc.Finally;
import play.mvc.Scope;

import javax.persistence.Column;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;

import static java.util.stream.Collectors.toList;

public class BaseJsonAPI  extends Controller {

    public static final String CSRF_KEY = "authenticityToken";
    public static final String HEADER_SILENCE = "x-silence";
    public static final String HEADER_CSRF_KEY = "x-authenticity-token";



    private final static ThreadLocal<ApiResponse> _apiResponse = new ThreadLocal<>();

    @Before
    public static void beforeApiRequest() {
        _apiResponse.set(new ApiResponse());
    }

    @Finally
    public static void cleanApiResponse() {
        _apiResponse.remove();
        ResponseUtility.setCorsHeaders();
    }


    public static String convertToColumnName(Object o,String name){
        if(StrUtil.isBlank(name)) return "";
        Class c = o.getClass();
        Field[] field = c.getDeclaredFields();
        String r = "";
        for (Field f : field) {
            if (f.getName().equals(name)) {
                Column t = (Column) f.getAnnotation(Column.class);
                r = t.name();
                break;
            }
        }
        if(StrUtil.isBlank(r)) {
            Class c1 = BaseModel.class;
            Field[] fields1 = c1.getFields();
            for (Field f : fields1) {
                if (f.getName().equals(name)) {
                    Column t = (Column) f.getAnnotation(Column.class);
                    r = t.name();
                    break;
                }
            }
        }
        return r;
    }

    protected static void renderFailMessage(int statusCode, String message) {
        renderFailMessage(statusCode, statusCode, message);
    }


    protected static void renderFailMessage(int respStatusCode, int messageCode, String message) {
        if (respStatusCode >= 200 && respStatusCode < 600) {
            response.status = respStatusCode;
        }
        setCode(messageCode);
        getApiResponse().message = message;
        processRenderApiResponse();
    }

    /**
     * 成功消息.
     */
    protected static void renderSuccMessage(String message) {
        String notice = Scope.Flash.current().get("notice");
        if (StrUtil.isNotBlank(notice)) {
            renderFailMessage(0, notice);
        }
        renderFailMessage(0, message);
    }

    /**
     * 返回Warn信息， http status=200
     */
    protected static void renderWarnMessage(int statusCode, String message) {
        setWarnMessage(message);
        setCode(statusCode);
        response.status = 200;
        processRenderApiResponse();
    }

    protected static Gson gson = new Gson();

    /**
     * 获取并验证对象.
     */
    protected static <T> T validateRequestBody(String key, Class<T> clazz) {
        T t = parseRequestBody(clazz);
        validateObject(key, t);
        return t;
    }
    protected static <T> T validateRequestBody(String body, String key, Class<T> clazz) {
        T t = parseRequestBody(body, clazz);
        validateObject(key, t);
        return t;
    }

    protected static void validateObject(String key, Object data) {
        Validation.valid(key, data);
        // 检查参数
        checkValidationErrors(key);
    }

    protected static <T> T parseRequestBody (Class<T> clazz) {
        String body = IO.readContentAsString(request.body);
        return parseRequestBody(body, clazz);
    }



    protected static <T> T parseRequestBody(String body, Class<T> clazz) {
        Logger.info("TLQ432820: body=%s", body);
        Logger.info( new Gson().toJson(body));
        if (StrUtil.isBlank(body)) {
            renderFailMessage("Empty Request Body");
        }
        return gson.fromJson(body, clazz);
    }

    protected static void renderFailMessage(String message) {
        String warn = Scope.Flash.current().get("warn");
        if (StrUtil.isNotBlank(warn)) {
            setWarnMessage(warn);
            renderFailMessage(400, message);
        }
        renderFailMessage(400, message);
    }

    // ---------- 设置返回参数的方法. ---------
    protected static ApiResponse getApiResponse() {
        if (_apiResponse.get() == null) {
            _apiResponse.set(new ApiResponse());
        }
        return _apiResponse.get();
    }

    /**
     * 输出数据对象
     *
     * @param data
     */
    protected static void renderData(Object data) {
        setData(data);
        processRenderApiResponse();
    }

    protected static void renderPaginator() {
//        setPageSize(pageQuery.getPageSize());
//        setPageNumber(pageQuery.getPageNumber());
//        setPageCount(pageQuery.getTotalRow());
//        setTotalPage(pageQuery.getTotalPage());
        Map<String, Object> resultMap = new HashMap<>();

        renderData(resultMap);
    }

    protected static <T> void renderPaginator(Paginator<Long, T> paginator) {
        renderPaginator(paginator, null);
    }

    protected static <T> void renderPaginator(Paginator<Long, T> paginator, Function<T, ?> mapperFunction) {
        setPageSize(paginator.getPageSize());
        setPageNumber(paginator.getPageNumber());
        setTotalCount(paginator.getRowCount());
        setTotalPage(paginator.getPageCount());

        Map<String, String> pageParamMap = new HashMap<>();
        pageParamMap.putAll(request.params.allSimple());
        pageParamMap.remove("body");

        getApiResponse().pageParams = pageParamMap;

        getApiResponse().hasNextPage = paginator.getHasNextPage();
        getApiResponse().hasPreviousPage = paginator.getHasPreviousPage();

        if (mapperFunction != null) {
            renderData(paginator.getCurrentPage().stream().map(mapperFunction).collect(toList()));
        } else {
            renderData(paginator.getCurrentPage());
        }
    }


    /**
     * 处理输出ApiResponse为JSON。
     *
     * 会处理flash信息，转化成正常的apiResponse参数.
     */
    private static void processRenderApiResponse() {
        // 处理flash中的warn
        String headerSilence = RequestUtility.getHeaderIgnoreCase(HEADER_SILENCE);

        if (!"true".equals(headerSilence)) {
            String warn = Scope.Flash.current().get("warn");
            if (StrUtil.isNotBlank(warn)) {
                Scope.Flash.current().remove("warn");
                setWarnMessage(warn);
            }

            // 处理flash中的notice
            String notice = Scope.Flash.current().get("notice");
            if (StrUtil.isNotBlank(notice)) {
                Scope.Flash.current().remove("notice");
                setNoticeMessage(notice);
            }
        }

        Scope.Flash.current().clear(); // 清除flash.data
        Scope.Flash.current().discard(); // 清除flash.out

        //logger.info("TLQ304240: getApiResponse()={}", GsonHelper.instance.toJson(getApiResponse()));

        renderApiResponse();
    }

    /**
     * 处理验证错误信息.
     */
    protected static void checkValidationErrors(String key) {
        ApiResponse apiResponse = getApiResponse();

        if (Validation.hasErrors()) {
            if (apiResponse.validationErrors == null) {
                apiResponse.validationErrors = new ArrayList<>();
            }
            for (Error error : Validation.errors()) {
                if (key == null || !key.equals(error.getKey())) { // 主表单的验证失败信息不需要返回给前端

                    // 在PATCH时，如果只是require，就跳过了
                    if (BeanHelper.patchModeCheck(() -> !"validation.required".equals(error.getMessageKey()))) {
                        KeyMessage valicationError = new KeyMessage();
                        valicationError.key = error.getKey();
                        valicationError.message = error.message();
                        apiResponse.validationErrors.add(valicationError);
                    }

                }
            }
            // 约定： 表单验证不通过 message code=90001
            // renderFailMessage(200, 90001, "参数验证错误");
            if (apiResponse.validationErrors.size() > 0) {
                Logger.info("LOG02503: 表单验证不通过" + apiResponse);
                renderFailMessage(400, "参数验证错误");
            }
        }
    }

    protected static void renderApiResponse() {
        String encoding = response.encoding;
        response.setContentTypeIfNotSet("application/javascript; charset=" + encoding);
        renderJSON(getApiResponse());
    }



    protected static void setNoticeMessage(String noticeMessage) {
        getApiResponse().noticeMessage = noticeMessage;
    }

    protected static void setWarnMessage(String warnMessage) {getApiResponse().warnMessage = warnMessage;}

    protected static void setPageSize(Integer pageSize) {
        getApiResponse().pageSize = pageSize;
    }


    protected static void setCode(Integer code) {
        getApiResponse().code = code;
    }

    protected static void setData(Object data) {
        getApiResponse().data = data;
    }

    protected static void setSummary(Object sumary) {
        getApiResponse().sumary = sumary;
    }


    protected static void setPageNumber(Integer pageNumber) {
        getApiResponse().pageNumber = pageNumber;
    }

    protected static void setTotalPage(Integer totalPage) {
        getApiResponse().totalPage = totalPage;
    }

    protected static void setTotalCount(Integer totalCount) {
        getApiResponse().totalCount = totalCount;
    }

    protected static void setPageCount(Integer pageCount) {
        getApiResponse().pageCount = pageCount;
    }






}
